import { EcsEntity } from "./EcsEntity";
import { EcsWorld } from "./EcsWorld";

class EntityEventListener {
	public obj: any = null;
	public call: Function = null;

}


function _sortEntityById(a: EcsEntity, b: EcsEntity) {
	if (a.id < b.id)
		return -1
	else
		return 1
}

export class EcsEntityGroup {
	private _addListener: EntityEventListener[] = [];
	private _deleteListener: EntityEventListener[] = [];
	private _replaceListener: EntityEventListener[] = [];
	private _entities: EcsEntity[] = [];
	private _compentsID: number = 0;
	public get entities(): EcsEntity[] { return this._entities; }

	private indexMap: { [key: number]: number } = {}

	public constructor(comps: number[], entities: { [key: number]: EcsEntity }) {
		this._compentsID = EcsEntityGroup.getGroupID(comps);

		for (let k in entities) {
			let _entity = entities[k];
			let _compsID: number = _entity.componentsID;
			if (this.isMatch(_compsID)) {
				this._entities.push(_entity);
			}
		}
		this._entities.sort(_sortEntityById);

		for (let index = 0; index < this._entities.length; index++) {
			const entity = this._entities[index];
			this.indexMap[entity.id] = index
		}
	}

	public clearAllListener(): void {
		this._addListener.length = 0;
		this._deleteListener.length = 0;
		this._replaceListener.length = 0;
	}

	public onAddListener(obj: any, call: Function): void {
		this._addListener.push({ obj: obj, call: call });
	}

	public onRemoveListener(obj: any, call: Function): void {
		this._deleteListener.push({ obj: obj, call: call });
	}

	public onReplaceListener(obj: any, call: Function): void {
		this._replaceListener.push({ obj: obj, call: call });
	}

	public add(world: EcsWorld, entity: EcsEntity): void {
		this._entities.push(entity);
		this.indexMap[entity.id] = this._entities.length - 1
		for (let i = 0; i < this._addListener.length; i++) {
			const _item = this._addListener[i];
			_item.call.call(_item.obj, world, entity);
		}
	}

	public remove(world: EcsWorld, entity: EcsEntity): void {
		const index = this.indexMap[entity.id]
		if (index || index == 0) {
			delete this.indexMap[entity.id]
			this._entities[index] = this._entities[this._entities.length - 1]
			const switchEcsEntity = this._entities[index]
			if (switchEcsEntity !== entity) {
				this.indexMap[switchEcsEntity.id] = index
			}
			this._entities.length -= 1
		}



		// for (let i = this._entities.length - 1; i >= 0; i--) {
		// 	if (this._entities[i] == entity) {

		// 		this._entities[i] = this._entities[this._entities.length - 1];

		// 		this._entities.length -= 1;
		// 		break;
		// 	}
		// }
		// for(let i=0;i<this._deleteListener.length;i++)
		// {
		// 	const _item = this._deleteListener[i];
		// 	_item.call.call(_item.obj,world,entity);
		// }
	}

	public replace(entity: EcsEntity, id: number): void {
		for (let i = 0; i < this._replaceListener.length; i++) {
			const _item = this._replaceListener[i];
			_item.call.call(_item.obj, entity, id);
		}
	}

	public isMatch(ids: number): boolean {
		return (this._compentsID & ids) == this._compentsID;
	}

	public static getGroupID(comps: number[]): number {
		let _id: number = 0;
		for (let i = 0; i < comps.length; i++) {
			_id += Math.pow(2, comps[i]);
		}
		return _id;
	}


}